package cn.wolfcode.ss.filter;

import cn.wolfcode.ss.utils.JWTUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 实现jwt拦截校验
        response.setContentType("application/json;charset=utf8");
        // 放行一些非拦截接口请求---/jwt/token
        String uri = request.getRequestURI();
        if (uri.startsWith("/jwt/login")){
            filterChain.doFilter(request, response);
            return;
        }
        // 校验jwt 合法性--是否存在， 是否能解析, 是否超时
        String token = request.getHeader("token");
        // 为空判断
        if ( ! StringUtils.hasText(token)){
            response.getWriter().write("token 不能为空");
            return;
        }
        // 合法性判断
        if ( ! JWTUtils.isExpired(token)) {
            response.getWriter().write("token 不合法或者失效");
            return;
        }

        // 因为配置是无状态登录，意味着登录成功之后的用户信息不会被session缓存
        // 此时需要要求每次访问校验jwt成功之后，需要将jwt转成 登录实体对象 Authentication
        // 目的：保证后续接口（controller中）执行能随时获取得到当前登录用户
        // 设置登录认证通过之后实体--

        String username = JWTUtils.getToken(token,"username");

        // 通过接口查询数据库中用户---原因：通过这个类可以将用户账号信息，密码，权限相关信息全部获取
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        if (userDetails == null) {
            response.getWriter().write("token校验失败，请重新登陆");
            return;
        }

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                userDetails.getUsername(),
                userDetails.getPassword(),
                userDetails.getAuthorities());

        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        filterChain.doFilter(request, response);
    }
}
